package com.mike.uaa.context;

import com.mike.uaa.core.Authentication;
import com.mike.uaa.core.GrantedAuthority;
import com.mike.uaa.core.User;
import com.mike.uaa.web.Exceptions;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;

/**
 * @author z
 */
public interface SecurityContext extends Serializable {


    /**
     * 获取当前经过身份认证的令牌
     *
     * @return 如果返回null则表示当前请求没有经过身份认证
     */
    Authentication getAuthentication();

    /**
     * 更改当前经过身份验证的主体，或删除身份验证信息。
     */
    void setAuthentication(Authentication authentication);


    default boolean unauthenticated() {
        return !authenticated();
    }

    default boolean authenticated() {
        Authentication authentication = getAuthentication();
        return authentication != null && authentication.isAuthenticated();
    }


    default void assertAuthenticated() {
        Authentication authentication = getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            throw Exceptions.createUnauthorizedException(Exceptions.USER_NOT_LOGIN.getMessage());
        }
    }

    /**
     * 获取当前主体的用户信息
     *
     * @return {@link User}
     */
    default User getUser() {
        Authentication authentication = getAuthentication();
        return authentication != null && authentication.isAuthenticated() ? (User) authentication.getPrincipal() : null;
    }

    /**
     * 获取当前用户的权限认证信息
     *
     * @return {@link GrantedAuthority}
     */
    default Collection<? extends GrantedAuthority> getAuthorities() {
        Authentication authentication = getAuthentication();
        return authentication != null && authentication.isAuthenticated() ? authentication.getAuthorities() : new HashSet<>();
    }

    /**
     * 检查是否有权限访问
     *
     * @param candidateAuthority 待检测权限信息
     * @return 返回检查结果 <code>true</code>检查通过
     */
    default boolean checkAuthority(String candidateAuthority) {
        return getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals(candidateAuthority));
    }

    /**
     * 检查是否有权限访问
     *
     * @param candidateAuthority 待检测权限信息
     * @return 返回检查结果 <code>true</code>检查通过
     */
    default boolean checkAuthority(GrantedAuthority candidateAuthority) {
        return getAuthorities().stream()
                .anyMatch(a -> a.equals(candidateAuthority));
    }

    default void assertAuthority(String candidateAuthority) {
        if (!checkAuthority(candidateAuthority)) {
            throw Exceptions.createForbiddenException(String.format("%s is not authorized", candidateAuthority));
        }
    }
}
